home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / nfsmount / nfsLookup.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-20  |  20.6 KB  |  701 lines

  1. /*
  2.  * nfsLookup.c --
  3.  * 
  4.  *    The main NFS pathname lookup procedure.  NFS does lookup component
  5.  *    at a time, while the Sprite interface is based on complete relative
  6.  *    names.  The NfsLookup procedure takes care of chopping the relative
  7.  *    name into components and doing NFS calls to get the handle for
  8.  *    each successive component.
  9.  *
  10.  * Copyright 1988 Regents of the University of California
  11.  * Permission to use, copy, modify, and distribute this
  12.  * software and its documentation for any purpose and without
  13.  * fee is hereby granted, provided that the above copyright
  14.  * notice appear in all copies.  The University of California
  15.  * makes no representations about the suitability of this
  16.  * software for any purpose.  It is provided "as is" without
  17.  * express or implied warranty.
  18.  */
  19. #ifndef lint
  20. static char rcsid[] = "$Header: /sprite/src/cmds/nfsmount/RCS/nfsLookup.c,v 1.5 91/10/20 12:38:28 mottsmth Exp $ SPRITE (Berkeley)";
  21. #endif not lint
  22.  
  23. #include "stdio.h"
  24.  
  25. #include "nfs.h"
  26. #include "sys/time.h"
  27. #include "sys/stat.h"
  28.  
  29. #include "kernel/fs.h"
  30.  
  31. static int ExpandLink();
  32. static void LookupCacheInsert();
  33. static int CheckMountPoint();
  34.  
  35. NfsReadTest() { return; } ;
  36.  
  37. /*
  38.  * This array holds the names of mount points within our namespace
  39.  * so that we can force redirect lookups. The array is initialized
  40.  * from the command line options using the callback function
  41.  * NfsRecordMountPointProc.
  42.  */
  43. #define MAXMOUNTPOINTS 10
  44.  
  45. typedef struct RedirectNode {
  46.     char *local;              /* Name (relative) in this filesystem */
  47.     char *remote;             /* Name (absolute) where subtree is mounted */
  48. } RedirectNode;
  49.  
  50. static RedirectNode redirectList[MAXMOUNTPOINTS];
  51. static int redirectCount = 0;
  52.  
  53.  
  54. /*
  55.  *----------------------------------------------------------------------
  56.  *
  57.  * NfsLookupTest --
  58.  *
  59.  *    Stub on top of NfsLookup to call it and exercise it.
  60.  * 
  61.  * Results:
  62.  *    None.
  63.  *
  64.  * Side effects:
  65.  *    Prints out the returned attributes of the file.
  66.  *
  67.  *----------------------------------------------------------------------
  68.  */
  69. void
  70. NfsLookupTest(private, name)
  71.     ClientData private;
  72.     char *name;
  73. {
  74.     NfsState *nfsPtr = (NfsState *)private;
  75.     diropokres dirResults;
  76.     diropargs dirArgs;
  77.     diropargs *dirArgsPtr = &dirArgs;
  78.     fattr *attrPtr = &dirResults.attributes;
  79.     int status;
  80.     char component[NFS_MAXNAMLEN];
  81.     Fs_RedirectInfo redirectInfo;
  82.  
  83.     dirArgs.name = component;
  84.     status = NfsLookup(nfsPtr, NULL , name, FS_FOLLOW,
  85.                &dirResults, &dirArgsPtr, &redirectInfo);
  86.     if (status == EREMOTE) {
  87.     printf("REDIRECT => \"%s\"\n", redirectInfo.fileName);
  88.     } else if (status == 0) {
  89.     register int *intPtr;
  90.  
  91.     printf("Handle of %s:%s/%s\n\t", nfsPtr->host, nfsPtr->nfsName, name);
  92.     NfsHandlePrint(&dirResults.file);
  93.     printf("\n");
  94.     printf("Parent handle\n\t");
  95.     NfsHandlePrint(&dirArgsPtr->dir);
  96.     printf("\n");
  97.  
  98.     printf("Attributes of %s:%s/%s\n", nfsPtr->host, nfsPtr->nfsName, name);
  99.     printf("\tFileID %x FS_ID %x\n",
  100.         attrPtr->fileid,
  101.         attrPtr->fsid);
  102.     printf("\tType %d mode 0%o links %d size %d\n",
  103.         attrPtr->type,
  104.         attrPtr->mode,
  105.         attrPtr->nlink,
  106.         attrPtr->size);
  107.     } else {
  108.     if (dirArgsPtr != (diropargs *)NULL) {
  109.         printf("Parent of %s\n\t", dirArgsPtr->name);
  110.         NfsHandlePrint(&dirArgsPtr->dir);
  111.         printf("\n");
  112.     }
  113.     printf("Lookup of %s:%s/%s returns <%d>\n",
  114.         nfsPtr->host, nfsPtr->nfsName, name, status);
  115.     }
  116. }
  117.  
  118. /*
  119.  *----------------------------------------------------------------------
  120.  *
  121.  * NfsLookup --
  122.  *
  123.  *    Called to return a nfs_fh for a path inside NFS.  Because NFS only
  124.  *    does component-at-a-time lookup we have to loop through the
  125.  *    pathname ourselves.  This routine is modeled very closely on
  126.  *    the Sprite kernel routine Fs_LocalLookup.
  127.  * 
  128.  * Results:
  129.  *    This returns an error code from NFS, or -1 if NFS access failed
  130.  *    entirely.  Upon NFS_OK return then *dirResultsPtr is filled in
  131.  *    with the handle and attributes for the name looked up.  If
  132.  *    dirArgsPtrPtr is non-null then this indirectly references storage
  133.  *    for the last pathname component and the handle of its parent.
  134.  *    This information is filled in if possible, otherwise the pointer
  135.  *    is cleared to indicate the information isn't available.
  136.  *    EREMOTE is returned if a symbolic link to the root was
  137.  *    encountered, or the pathname left via ".." out the top of the
  138.  *    NFS system.  *redirectInfoPtr gets filled in with the new
  139.  *    pathname in this case.
  140.  *
  141.  * Side effects:
  142.  *    None (yet).
  143.  *
  144.  *----------------------------------------------------------------------
  145.  */
  146. int
  147. NfsLookup(nfsPtr, cwdFilePtr, name, useFlags, dirResultsPtr, dirArgsPtrPtr,
  148.     redirectInfoPtr)
  149.     NfsState *nfsPtr;        /* Top level state for NFS connection */
  150.     NfsOpenFile *cwdFilePtr;    /* Handle for directory at start of path.
  151.                  * If NULL the mount point is used. */
  152.     char *name;            /* Name relative to cwdHandle */
  153.     int useFlags;        /* Sprite Lookup flags.  FS_FOLLOW means
  154.                  * follow symbolic links. */
  155.     diropokres *dirResultsPtr;    /* Return - handle and attributes of name */
  156.     diropargs **dirArgsPtrPtr;    /* If non-NULL **dirArgsPtrPtr is filled in
  157.                  * with the last component of name and the
  158.                  * handle for the parent directory.  This is
  159.                  * used when creating, removing, etc. Note
  160.                  * that (*dirArgsPtrPtr)->name must point
  161.                  * to storage for the pathname component. */
  162.     Fs_RedirectInfo *redirectInfoPtr; /* Returned name if a symbolic link to the
  163.                  * root is encountered.  Return value of
  164.                  * the procedure is EREMOTE in this case. */
  165. {
  166.     register char *curCharPtr;
  167.     register int compLen = -1;
  168.     register char *compPtr;
  169.     register nfs_fh *cwdHandlePtr;
  170.     register int status = (int) NFS_OK;
  171.     int numLinks = 0;
  172.     int haveGoodAttrs = 0;
  173.     diropargs *returnDirArgsPtr;
  174.     diropargs dirArgs;
  175.     diropres dirResults;
  176.     char component[NFS_MAXNAMLEN];
  177.     char expandedPath[NFS_MAXNAMLEN];
  178.     int isMountPoint;
  179.  
  180.     /*
  181.      * Initialize lookup.  Skip leading slashs, get a handle for the
  182.      * current starting point, fill in the diropargs that we'll be
  183.      * passing to the NFS server.
  184.      */
  185.     redirectInfoPtr->prefixLength = 0;        /* no remote links in NFS */
  186.     if (dirArgsPtrPtr != (diropargs **)NULL) {
  187.     returnDirArgsPtr = *dirArgsPtrPtr;
  188.     *dirArgsPtrPtr = (diropargs *)NULL;    /* to indicate no parent, yet */
  189.     } else {
  190.     returnDirArgsPtr = (diropargs *)NULL;
  191.     }
  192.     curCharPtr = name;
  193.     while (*curCharPtr && *curCharPtr == '/') {
  194.     curCharPtr++;
  195.     }
  196.     if (cwdFilePtr == (NfsOpenFile *)NULL) {
  197.     cwdHandlePtr = nfsPtr->mountHandle;
  198.     } else {
  199.     cwdHandlePtr = cwdFilePtr->handlePtr;
  200.     }
  201.     dirArgs.name = component;
  202.     /*
  203.      * Loop through the pathname.
  204.      */
  205.     while (*curCharPtr != '\0') {
  206.     /*
  207.      * Copy the next component and skip trailing slashes.
  208.      */
  209.     compPtr = component;
  210.     while (*curCharPtr != '/' && *curCharPtr != '\0') {
  211.         *compPtr++ = *curCharPtr++;
  212.     }
  213.     compLen = compPtr - component;
  214.     if (compLen >= NFS_MAXNAMLEN) {
  215.         status = NFSERR_NAMETOOLONG;
  216.         goto exit;
  217.     }
  218.     *compPtr = '\0';
  219.     bcopy((char *)cwdHandlePtr, (char *)&dirArgs.dir, sizeof(nfs_fh));
  220.  
  221.     isMountPoint = (bcmp((char *)cwdHandlePtr,
  222.               (char *)nfsPtr->mountHandle,
  223.               NFS_FHSIZE) == 0);
  224.  
  225.     if ((isMountPoint) &&
  226.         (CheckMountPoint(component,redirectInfoPtr->fileName) >= 0)) {
  227.         (void)strcat(redirectInfoPtr->fileName, curCharPtr);
  228.         return(EREMOTE);
  229.     }
  230.  
  231.     while (*curCharPtr == '/') {
  232.         curCharPtr++;
  233.     }
  234.     if (compLen == 2 && component[0] == '.' && component[1] == '.') {
  235.         /*
  236.          * Going to the parent directory, "..".
  237.          */
  238.         if (isMountPoint) {
  239.         /*
  240.          * We are falling off the top of the NFS system.  Copy the
  241.          * remaining part of the name, including the "../", into
  242.          * *newNamePtr and return that, instead of a handle.
  243.          */
  244.         (void)strcpy(redirectInfoPtr->fileName, "../");
  245.         (void)strcat(redirectInfoPtr->fileName, curCharPtr);
  246.         return(EREMOTE);
  247.         }
  248.     } else if (compLen == 1 && component[0] == '.') {
  249.         /*
  250.          * Already have a handle on ".", the current directory.
  251.          */
  252.         continue;
  253.     }
  254.     /*
  255.      * Lookup the next component via NFS.  Remember that the current
  256.      * handle has been copied into dirArgs, and the result handle
  257.      * will be copied into dirResults by the XDR routines.
  258.      */
  259.     if (clnt_call(nfsPtr->nfsClnt, NFSPROC_LOOKUP, xdr_diropargs, &dirArgs,
  260.             xdr_diropres, &dirResults, nfsTimeout) != RPC_SUCCESS) {
  261.         clnt_perror(nfsPtr->nfsClnt, "NfsLookup: RPC nfsproc_lookup_2");
  262.         status = -1;
  263.         goto exit;
  264.     } else if (dirResults.status != NFS_OK) {
  265.         /*
  266.          * Lookup failed.  If we failed on the last component we set up
  267.          * the returned dirArgs so they are useful for a subsequent
  268.          * create.  returnDirArgsPtr is the original pointer to
  269.          * good storage provided by our caller.  We set the pointer
  270.          * to this pointer to indicate the storage now has valid data.
  271.          */
  272.         status = (int)dirResults.status;
  273.         if (*curCharPtr == '\0' && returnDirArgsPtr != (diropargs *)NULL) {
  274.         bcopy((char *)&dirArgs.dir, (char *)&returnDirArgsPtr->dir,
  275.             sizeof(nfs_fh));
  276.         strcpy(returnDirArgsPtr->name, component);
  277.         *dirArgsPtrPtr = returnDirArgsPtr;
  278.         }
  279.         goto exit;
  280.     } else {
  281.         /*
  282.          * Lookup succeeded.  The lookup result is cached for
  283.          * a brief period to optimize heavy traffic through top-level
  284.          * directories.
  285.          */
  286.         haveGoodAttrs = 1;
  287.         cwdHandlePtr = &dirArgs.dir;
  288.         LookupCacheInsert(cwdHandlePtr, component, &dirResults);
  289.  
  290.         if ((*curCharPtr != '\0' || (useFlags & FS_FOLLOW)) &&
  291.         dirResults.diropres_u.diropres.attributes.type == NFLNK) {
  292.         /*
  293.          * Hit a symbolic link in the middle of a pathname or at
  294.          * the end are we are told to follow it.
  295.          */
  296.         numLinks++;
  297.         if (numLinks > FS_MAX_LINKS) {
  298.             status = ELOOP;
  299.             goto exit;
  300.         } else {
  301.             int offset;        /* Distance of existing name from the
  302.                      * start of its buffer */
  303.             if (numLinks == 1) {
  304.             offset = (int)curCharPtr - (int)name;
  305.             } else {
  306.             offset = (int)curCharPtr -
  307.                  (int)(expandedPath);
  308.             }
  309.             status = ExpandLink(nfsPtr, &dirResults, curCharPtr, offset,
  310.                     expandedPath);
  311.             if (status != NFS_OK) {
  312.             goto exit;
  313.             }
  314.             curCharPtr = expandedPath;
  315.         }
  316.         if (*curCharPtr == '/') {
  317.             /*
  318.              * A link back to the root has to be handled by the
  319.              * prefix table in the Sprite kernel.
  320.              */
  321.             strcpy(redirectInfoPtr->fileName, expandedPath);
  322.             return(EREMOTE);
  323.         }
  324.         /*
  325.          * The link was relative so we reset the current handle
  326.          * to point to the same place we found the link.
  327.          */
  328.         cwdHandlePtr = &dirArgs.dir;
  329.          } else {
  330.          /*
  331.           * Not a symbolic link.
  332.           * Advance the current handle to the component we just found.
  333.           */
  334.          cwdHandlePtr = &dirResults.diropres_u.diropres.file;
  335.          }
  336.     }
  337.     }
  338.     /*
  339.      * Lookup complete.  Copy out our results.
  340.      */
  341.     if (haveGoodAttrs) {
  342.     bcopy((char *)&dirResults.diropres_u.diropres, (char *)dirResultsPtr,
  343.         sizeof(diropokres));
  344.     if (returnDirArgsPtr != (diropargs *)NULL) {
  345.         /*
  346.          * Our caller wants information about the parent directory
  347.          * for a delete, rename, or link.  We restore the pointer
  348.          * to indicate that this information has been provided.
  349.          */
  350.         bcopy((char *)&dirArgs.dir, (char *)&returnDirArgsPtr->dir,
  351.             sizeof(nfs_fh));
  352.         strcpy(returnDirArgsPtr->name, component);
  353.         *dirArgsPtrPtr = returnDirArgsPtr;
  354.     }
  355.     } else {
  356.     /*
  357.      * We didn't go throught the lookup loop because our caller asked
  358.      * for an empty name.  We do an explicit get attributes.
  359.      */
  360.     register attrstat *tmpAttrPtr;
  361.     tmpAttrPtr = nfsproc_getattr_2(cwdHandlePtr, nfsPtr->nfsClnt);
  362.     if (tmpAttrPtr == (attrstat *)NULL) {
  363.         clnt_perror(nfsPtr->nfsClnt, "NfsLookup: RPC  nfsproc_getattr_2");
  364.         status = -1;
  365.         goto exit;
  366.     } else if (tmpAttrPtr->status != NFS_OK) {
  367.         status = (int)tmpAttrPtr->status;
  368.         goto exit;
  369.     } else {
  370.         bcopy((char *)cwdHandlePtr, (char *)&dirResultsPtr->file,
  371.             NFS_FHSIZE);
  372.         bcopy((char *)&tmpAttrPtr->attrstat_u.attributes,
  373.           (char *)&dirResultsPtr->attributes, sizeof(fattr));
  374.     }
  375.     }
  376. exit:
  377.     if (status == -1 && errno != 0) {
  378.     status = errno;
  379.     }
  380.     return(status);
  381. }
  382.  
  383. /*
  384.  *----------------------------------------------------------------------
  385.  *
  386.  * LookupCacheInsert --
  387.  *
  388.  *    Tuck away a <nfs_fh, component> => <nfs_fh> mapping.
  389.  * 
  390.  * Results:
  391.  *    None.
  392.  *
  393.  * Side effects:
  394.  *    Adds an entry into the component cache.
  395.  *
  396.  *----------------------------------------------------------------------
  397.  */
  398. static void
  399. LookupCacheInsert(component, dirResultsPtr)
  400.     char *component;        /* Pathname component just looked up. */
  401.     diropres *dirResultsPtr;    /* Return info from NFS server */
  402. {
  403.     return;
  404. }
  405.  
  406. /*
  407.  *----------------------------------------------------------------------
  408.  *
  409.  * ExpandLink --
  410.  *    Expand a link by shifting the remaining pathname over and
  411.  *    inserting the contents of the link file.
  412.  *
  413.  * Results:
  414.  *    None.
  415.  *
  416.  * Side effects:
  417.  *    Expands the link into nameBuffer.
  418.  *
  419.  *----------------------------------------------------------------------
  420.  */
  421. static int
  422. ExpandLink(nfsPtr, dirResultsPtr, curCharPtr, offset, nameBuffer)
  423.     NfsState    *nfsPtr;        /* Needed for ReadLink RPC */
  424.     diropres    *dirResultsPtr;        /* Handle + attrs of the link file */
  425.     char    *curCharPtr;        /* Points to beginning of the remaining
  426.                      * name that has to be shifted */
  427.     int        offset;            /* Offset of curCharPtr within its 
  428.                      * buffer */
  429.     char     nameBuffer[];        /* New buffer for the expanded name */
  430. {
  431.     ReturnStatus     status;
  432.     int         linkNameLength;    /* The length of the name in the
  433.                      * link NOT including the Null */
  434.     readlinkres        readLinkResult;
  435.     char        savedC;
  436.     register char     *srcPtr;
  437.     register char     *dstPtr;
  438.  
  439.     linkNameLength = dirResultsPtr->diropres_u.diropres.attributes.size;
  440.     if (*curCharPtr == '\0') {
  441.     /*
  442.      * There is no pathname to shift around.
  443.      * Make sure the new name is null terminated
  444.      */
  445.     nameBuffer[linkNameLength] = '\0';
  446.     } else {
  447.     /*
  448.      * Set up srcPtr to point to the start of the remaining pathname.
  449.      * Set up dstPtr to point to just after where the link will be,
  450.      * ie. just where the '/' is that separates the link value from
  451.      * the remaining pathname.
  452.      */
  453.     srcPtr = curCharPtr;
  454.     dstPtr = &nameBuffer[linkNameLength];
  455.     if (linkNameLength < offset) {
  456.         /*
  457.          * The remaining name has to be shifted left.
  458.          * For example, /first is a link to /usr (or /users).  With the
  459.          * filename /first/abc, curCharPtr will point to the 'a' in "abc".
  460.          * dstPtr points to the '\0' after "/usr".
  461.          *
  462.          *  / f i r s t / a b c \0        { current name, offset = 7 }
  463.          *  / u s r \0            { link name, len = 4 }
  464.          *  / u s e r s \0            {   or len = 6 }
  465.          *  / u s r / a b c            { final result }
  466.          *
  467.          * Insert the separating '/' first, then start at the beginning
  468.          * of the remaining name and copy it into the new buffer.
  469.          */
  470.         *dstPtr = '/';
  471.         dstPtr++;
  472.         for( ; ; ) {
  473.         *dstPtr = *srcPtr;
  474.             if (*srcPtr == '\0') {
  475.             break;
  476.         }
  477.         dstPtr++;
  478.         srcPtr++;
  479.         }
  480.     } else {
  481.         /*
  482.          * The remaining name has to be shifted right.
  483.          * For example, /first is a link to /usr/tmp.  With the filename
  484.          * /first/abc, curCharPtr will point to the 'a' in "abc".
  485.          * dstPtr points to the '\0' after "/usr/tmp".
  486.          *
  487.          * / f i r s t / a b c \0        { current name, offset = 7 }
  488.          * / u s r / t m p \0        { link name, len = 8 }
  489.          * / u s r / t m p / a b c        { final result }
  490.          * 
  491.          * Zoom to the end of the name (adjusting dstPtr to account
  492.          * for where the '/' will go) and then shift the name right.
  493.          */
  494.         dstPtr++;
  495.         while (*srcPtr != '\0') {
  496.         srcPtr++;
  497.         dstPtr++;
  498.         }
  499.         while (srcPtr >= curCharPtr) {
  500.         *dstPtr = *srcPtr;
  501.         dstPtr--;
  502.         srcPtr--;
  503.         }
  504.         *dstPtr = '/';
  505.     }
  506.     }
  507.     /*
  508.      * Read and insert the link name in front of the remaining name
  509.      * that was just shifted over.  By initializing the character string
  510.      * pointer (data) before the RPC the XDR routines know to use
  511.      * the existing buffer and not allocate a new one.  Also, the XDR routines
  512.      * are going to null terminate the string and stomp on the character
  513.      * after the link value, so we save and restore that.
  514.      */
  515.     readLinkResult.readlinkres_u.data = nameBuffer;
  516.     savedC = nameBuffer[linkNameLength];
  517.     if (clnt_call(nfsPtr->nfsClnt, NFSPROC_READLINK, xdr_nfs_fh,
  518.         &dirResultsPtr->diropres_u.diropres.file, xdr_readlinkres,
  519.         &readLinkResult, nfsTimeout) != RPC_SUCCESS) {
  520.     clnt_perror(nfsPtr->nfsClnt, "nfsproc_lookup_2");
  521.     if (errno != 0) {
  522.         return(errno);
  523.     } else {
  524.         return(-1);
  525.     }
  526.     }
  527.     nameBuffer[linkNameLength] = savedC;
  528.     return(readLinkResult.status);
  529. }
  530.  
  531. /*
  532.  *----------------------------------------------------------------------
  533.  *
  534.  * NfsWriteTest --
  535.  *
  536.  *    Test harness for NFS writing.  This opens a NFS file and copies
  537.  *    a Sprite file to an NFS file.
  538.  * 
  539.  * Results:
  540.  *    None.
  541.  *
  542.  * Side effects:
  543.  *    Prints out the returned attributes of the file.
  544.  *
  545.  *----------------------------------------------------------------------
  546.  */
  547. void
  548. NfsWriteTest(private, spriteName, nfsName)
  549.     ClientData private;
  550.     char *spriteName;
  551.     char *nfsName;
  552. {
  553.     NfsState *nfsPtr = (NfsState *)private;
  554.     diropres longDirResults;
  555.     diropokres *dirResultsPtr = &longDirResults.diropres_u.diropres;
  556.     int status;
  557.     char *newName;
  558.     createargs createArgs;
  559.     diropargs *wherePtr = &createArgs.where;
  560.     sattr *sattrPtr = &createArgs.attributes;
  561.     char component[NFS_MAXNAMLEN];
  562.     Fs_RedirectInfo redirectInfo;
  563.  
  564.     wherePtr->name = component;
  565.     status = NfsLookup(nfsPtr, NULL /* fix */, nfsName,
  566.             FS_FOLLOW, dirResultsPtr, &wherePtr, &redirectInfo);
  567.     if (status == EREMOTE) {
  568.     printf("REDIRECT => \"%s\"\n", redirectInfo.fileName);
  569.     } else if (status == NFSERR_NOENT && wherePtr != (diropargs *)NULL) {
  570.     sattrPtr->mode = 0644;
  571.     sattrPtr->uid = 1020;    /* non-existent! */
  572.     sattrPtr->gid = 94;        /* non-existent! */
  573.     sattrPtr->size = 0;
  574.     sattrPtr->atime.seconds = -1;
  575.     sattrPtr->atime.useconds = -1;
  576.     sattrPtr->mtime.seconds = -1;
  577.     sattrPtr->mtime.useconds = -1;
  578.     if (clnt_call(nfsPtr->nfsClnt, NFSPROC_CREATE, xdr_createargs,
  579.         &createArgs, xdr_diropres, &longDirResults, nfsTimeout)
  580.             != RPC_SUCCESS) {
  581.         clnt_perror(nfsPtr->nfsClnt, "NFSPROC_CREATE");
  582.         return;
  583.     }
  584.     status = longDirResults.status;
  585.     printf("Create of %s:%s/%s returns <%d>\n",
  586.         nfsPtr->host, nfsPtr->nfsName, nfsName, status);
  587.  
  588.     } else {
  589.     printf("Lookup of %s:%s/%s returns <%d>\n",
  590.         nfsPtr->host, nfsPtr->nfsName, nfsName, status);
  591.     }
  592. }
  593.  
  594.  
  595.  
  596. /*
  597.  *----------------------------------------------------------------------
  598.  *
  599.  * NfsRecordMountPointProc --
  600.  *
  601.  *    Add a sub-mount point to our list.
  602.  * 
  603.  *      This routine is called by the Opt_Parse routine when it sees 
  604.  *      a -m option.
  605.  *
  606.  * Results:
  607.  *    None.
  608.  *
  609.  * Side effects:
  610.  *    None.
  611.  *
  612.  * Note:
  613.  *      NFS allows one file system to be mounted within another NFS
  614.  *      namespace.  This causes problems for Sprite since it expects
  615.  *      to have a remote link at each mount point. The kluge of a
  616.  *      solution is to tell nfsmount where the sub-mount points are
  617.  *      in its namespace so that it can return EREMOTE when a lookup
  618.  *      enters one of these subdomains.
  619.  *
  620.  *----------------------------------------------------------------------
  621.  */
  622.  
  623. int
  624. NfsRecordMountPointProc(option, argc, argv)
  625.     char *option;             /* should point to 'm' */
  626.     int argc;                 /* number of remaining args */
  627.     char **argv;              /* arg pointers */
  628. {
  629.     int i;
  630.     struct stat statBuf;
  631.  
  632.     if ((argc < 2) ||
  633.     (*argv[0] == '-') ||
  634.     (*argv[0] == '/') ||
  635.     (*argv[1] != '/')) {
  636.     fprintf(stderr, "Usage -m option: relative-local-name absolute-remote-name\n");
  637.         exit(-1);
  638.     }
  639.  
  640.     if (redirectCount >= MAXMOUNTPOINTS) {
  641.     fprintf(stderr, "Too many mount points specified. (%d max)\n",
  642.         MAXMOUNTPOINTS);
  643.         exit(-1);
  644.     }
  645.  
  646.     if (lstat(argv[1], &statBuf) < 0) {
  647.     perror(argv[1]);
  648.     exit(-1);
  649.     }
  650.  
  651.     if ((statBuf.st_mode & S_IFMT) != S_IFRLNK) {
  652.     fprintf(stderr,"Not a remote link: %s\n", argv[1]);
  653.     exit(-1);
  654.     }
  655.  
  656.     redirectList[redirectCount].local = argv[0];
  657.     redirectList[redirectCount].remote = argv[1];
  658.     redirectCount++;
  659.     
  660.     for (i=0,argc-=2; i<argc; i++) {
  661.     argv[i] = argv[i+2];
  662.     }
  663.  
  664.     /* tell Opt_Parse that we consumed 2 arguments */
  665.     return argc;
  666. }
  667.  
  668. /*
  669.  *----------------------------------------------------------------------
  670.  *
  671.  * CheckMountPoint --
  672.  *
  673.  *    Check a name against the mount point list.
  674.  * 
  675.  * Results:
  676.  *    None.
  677.  *
  678.  * Side effects:
  679.  *    Uses but does not modify the global redirectList.
  680.  *
  681.  *----------------------------------------------------------------------
  682.  */
  683.  
  684. static int
  685. CheckMountPoint(name, redirectPtr)
  686.     char *name;               /* name of local file to verify */
  687.     char *redirectPtr;        /* name to redirect to */
  688. {
  689.     int i;
  690.  
  691.     for (i=0; i<redirectCount; i++) {
  692.     if (strcmp(redirectList[i].local,name) == 0) {
  693.         strcpy(redirectPtr, redirectList[i].remote);
  694.         return i;
  695.     }
  696.     }
  697.  
  698.     return -1;
  699.  
  700. }
  701.